﻿using System;
using System.Buffers;
using System.IO;
using System.Net.Security;
using System.Threading;
using Deer.Constant;
using Letter.IO.Binary;
using Letter.IO.Pipes;
using Letter.Net.Tcp;

namespace Telex;

delegate void SocketMessageDelegate(byte command, ref BytesReader reader);

abstract class ARcpConnection : ADefaultFixedHeaderBytesConnection
{
    public ARcpConnection(ref ConnectionFixedConfig config) : base(config.order)
    {
        this.Initialization(ref config);
    }

    public ARcpConnection(ref ConnectionFixedConfig config, SslOptions sslOptions, Func<Stream, SslStream> sslStreamFactory)
        : base(config.order, sslOptions, sslStreamFactory)
    {
        this.Initialization(ref config);
    }

    private void Initialization(ref ConnectionFixedConfig config)
    {
        this.localHost = config.host;
        this.secretkey = config.secretkey;
        this.onConnect = config.onConnect;
        this.onDisconnect = config.onDisconnect;
    }

    protected RpcHost localHost;
    protected RpcHost remoteHost;
    protected string secretkey;
    protected Action<ARcpConnection> onConnect;
    protected Action<ARcpConnection> onDisconnect;
    protected int connectionState = Booleans.FALSE;

    public SocketMessageDelegate OnSocketMessageDelegate;

    public RpcHost LocalHost
    {
        get { return this.localHost; }
    }

    public RpcHost RemoteHost
    {
        get { return this.remoteHost; }
    }

    public new IDuplexPipeline Pipelines
    {
        get { return base.Pipelines; }
    }

    protected override void OnActive()
    {
        base.OnActive();
    }
    
    protected virtual void OnRcvSyncHost(ref BytesReader reader)
    {
        Interlocked.Exchange(ref connectionState, Booleans.TRUE);
        
        var cLength = reader.ReadInt32BE();
        var cBuf = reader.ReadBuffer(cLength);
        var cId = System.Text.Encoding.UTF8.GetString(cBuf.ToArray());

        var sLength = reader.ReadInt32BE();
        var sBuf = reader.ReadBuffer(sLength);
        var sId =  System.Text.Encoding.UTF8.GetString(sBuf.ToArray());

        this.remoteHost = new RpcHost(cId, sId);
        
        this.onConnect?.Invoke(this);
    }

    protected void OnRcvSocketMessage(byte command, ref BytesReader reader)
    {
        OnSocketMessageDelegate?.Invoke(command, ref reader);
    }
    
    protected override void OnInactive()
    {
        if (connectionState == Booleans.TRUE)
        {
            this.onDisconnect?.Invoke(this);    
        }
        
        base.OnInactive();
    }
}

struct ConnectionFixedConfig
{
    public RpcHost host;
    public BinaryOrder order;
    public string secretkey;
    public Action<ARcpConnection> onConnect;
    public Action<ARcpConnection> onDisconnect;
}
